/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

package scenic.toolkit.db;


public abstract class MultiArray extends Node {
	private int size[];
	private int capacity;
	private ArrayType type;
	
	public MultiArray(ArrayType type, int ndim) {
		this.type = type;
		size = new int[ndim];
	}
	
	public Node getNode() {
		return this;
	}
	
	public ArrayType getType() {
		return type;
	}
	
	static private int getNumElements(int size[])
	{
		int n = 1;
		
		for(int i = 0; i < size.length; i++)
			n *= size[i];
		
		return n;
	}
	
	static private int getNumElements(int size[], int dim)
	{
		int n = 1;
		
		for(int i = dim; i < size.length; i++)
			n *= size[i];
		
		return n;
	}
	
	static protected int getIndex(int size[], int position[])
	{
		int n = 1;
		int p = 0;
		
		for(int i = 0; i < size.length; i++) {
			p += position[i] * n;
			n *= size[i];
		}
		
		return p;
	}
	
	protected static void copy(Object src, int soff, int sp[],int srcSize[], 
			Object dst, int doff, int dp[], int dstSize[], int size[], int dim)
	{
		if(dim == srcSize.length - 1) {
			System.arraycopy(src, soff + sp[dim], dst, doff + dp[dim], size[dim]);			
		} else {
			int sStep = getNumElements(srcSize, dim + 1);
			int dStep = getNumElements(dstSize, dim + 1);
			
			soff += sp[dim] * sStep;
			doff += dp[dim] * dStep;
			for(int i = 0; i < size[dim]; i++) {
				copy(src, soff, sp, srcSize, dst, doff, dp, dstSize, size, dim + 1);
				soff += sStep;
				doff += dStep;				
			}
		}
	}
	
	protected static void copy(Object src, int sp[],int srcSize[], 
			Object dst, int dp[], int dstSize[], int size[])
	{
		copy(src, 0, sp, srcSize, dst, 0, dp, dstSize, size, 0);
	}
	
	protected static void copy(Object src, int srcSize[], 
			Object dst, int dstSize[])
	{	
		int p[] = new int[srcSize.length];
		int size[] = new int[srcSize.length];
		
		for(int i = 0; i < srcSize.length; i++)
			size[i] = Math.min(srcSize[i], dstSize[i]);
			
		copy(src, p, srcSize, dst, p, dstSize, size);
	}
	
	public void setSize(int newSize[]) {
		if(size.length != newSize.length)
			throw new IllegalArgumentException("Wrong number of dimensions");
		capacity = getNumElements(newSize);
		Object newData = allocate(capacity);
		copy(getData(), size, newData, newSize);
		for(int i = 0; i < newSize.length; i++)
			size[i] = newSize[i];
		setData(newData);
	}
	
	public void setSize(int newSize) {
		setSize(new int[] { newSize } );
	}
	
	public int[] getSize() {
		return size;
	}
	
	public int getLength() {
		return size[0];
	}
	
	protected abstract Object getData();
	
	protected abstract void setData(Object data);
	
	protected abstract Object allocate(int size);
	/*
	protected void write(int position, Object array, int length) throws IndexOutOfBoundsException {
		write(new int[] { position }, array, new int[] { length } );
	}
	
	protected void write(int position[], Object array, int size[]) throws IndexOutOfBoundsException {
		int ndim = this.size.length;
		
		if(ndim != position.length || ndim != size.length)
			throw new IllegalArgumentException("Wrong number of dimensions");
		for(int i = 0; i < ndim; i++)
			if(position[i] < 0 || position[i] + size[i] > this.size[i])
				throw new IndexOutOfBoundsException();
		copy(array, position, size, getData(), new int[ndim], this.size, size);
		notifyChange(new ArrayWriteEvent(this, position, size));
	}
	
	protected void insert(int dim, int position, Object array, int length) {
		if(position < 0 || position > size[0])
			throw new IndexOutOfBoundsException();
		int newSize[] = new int[size.length];
		int s2[] = new int[size.length];
		int p[] = new int[size.length];
		int p2[] = new int[size.length];
		int zp[] = new int[size.length];

		for(int i = 0; i < size.length; i++)
			newSize[i] = size[i];
		newSize[dim] += length;
		for(int i = 0; i < size.length; i++)
			s2[i] = size[i];
		s2[dim] = position;
		p[dim] = position;
		p2[dim] = position + length;
		capacity = getNumElements(newSize);
		Object newData = allocate(capacity);
		copy(getData(), zp, size, newData, zp, newSize, s2);
		s2[dim] = size[dim] - position;
		copy(getData(), p, size, newData, p2, newSize, s2);
		s2[dim] = length;
		copy(array, zp, s2, newData, p, newSize, s2);
		for(int i = 0; i < newSize.length; i++)
			size[i] = newSize[i];
		setData(newData);
	}

	public void remove(int position, int length) {
		if(position < 0 || position + length > this.size)
			throw new IndexOutOfBoundsException();
		System.arraycopy(getData(), position + length, getData(), position, 
				size - (position + length));
		size -= length;
		notifyRemove(position, length);
	}
	
	public void move(int src, int dest, int length) {
		if(src < 0 || src + length > this.size 
				|| dest < 0 || dest + length > this.size )
			throw new IndexOutOfBoundsException();	
	}
	
	protected void notifyWrite(int position, int length) {
		notifyChange(new ArrayWriteEvent(this, position, length));
	}
	
	protected void notifyRemove(int position, int length) {
		notifyChange(new ArrayRemoveEvent(this, position, length));
	}
	
	protected void notifyInsert(int position, int length) {
		notifyChange(new ArrayInsertEvent(this, position, length));
	} */
}
